home *** CD-ROM | disk | FTP | other *** search
/ World of Video / World of Video.iso / datafiles / gfx_formats / gif / dither2.txt < prev    next >
Text File  |  1995-02-13  |  28KB  |  549 lines

  1. DITHER.TXT
  2.  
  3. What follows is everything you ever wanted to know (for the time being) about 
  4. dithering.  I'm sure it will be out of date as soon as it is released, but it 
  5. does serve to collect data from a wide variety of sources into a single 
  6. document, and should save you considerable searching time.  
  7.  
  8. Numbers in brackets (like this [0]) are references.  A list of these works 
  9. appears at the end of this document.  
  10.  
  11. Because this document describes ideas and algorithms which are constantly 
  12. changing, I expect that it may have many editions, additions, and corrections 
  13. before it gets to you.  I will list my name below as original author, but I 
  14. do not wish to deter others from adding their own thoughts and discoveries.  
  15. This is not copyrighted in any way, and was created solely for the purpose of 
  16. organizing my own knowledge on the subject, and sharing this with others.  
  17. Please distribute it to anyonw who might be interested.  
  18.  
  19. If you add anything to this document, please feel free to include your name 
  20. below as a contributor or as a reference.  I would particularly like to see 
  21. additions to the "Other books of interest" section.  Please keep the text in 
  22. this simple format: no margins, no pagination, no lines longer that 79 
  23. characters, and no non-ASCII or non-printing characters other than a CR/LF 
  24. pair at the end of each line.  It is intended that this be read on as many 
  25. different machines as possible.  
  26.  
  27. Original Author:
  28.  
  29. Lee Crocker                 I can be reached in the CompuServe Graphics
  30. 1380 Jewett Ave             Support Forum (GO PICS) with ID # 73407,2030.
  31. Pittsburg, CA  94565
  32.  
  33. Contributors:
  34.  
  35. ========================================================================
  36. What is Dithering?
  37.  
  38. Dithering, also called Halftoning or Color Reduction, is the process of 
  39. rendering an image on a display device with fewer colors than are in the 
  40. image.  The number of different colors in an image or on a device I will call 
  41. its Color Resolution.  The term "resolution" means "fineness" and is used to 
  42. describe the level of detail in a digitally sampled signal.  It is used most 
  43. often in referring to the Spatial Resolution, which is the basic sampling 
  44. rate for a digitized image.  
  45.  
  46. Spatial resolution describes the fineness of the "dots" used in an image.  
  47. Color resolution describes the fineness of detail available at each dot.  The 
  48. higher the resolution of a digital sample, the better it can reproduce high 
  49. frequency detail.  A compact disc, for example, has a temporal (time) 
  50. resolution of 44,000 samples per second, and a dynamic (volume) resolution of 
  51. 16 bits (0..65535).  It can therefore reproduce sounds with a vast dynamic 
  52. range (from barely audible to ear-splitting) with great detail, but it has 
  53. problems with very high-frequency sounds, like violins and piccolos.  
  54.  
  55. It is often possible to "trade" one kind of resolution for another.  If your 
  56. display device has a higher spatial resolution than the image you are trying 
  57. to reproduce, it can show a very good image even if its color resolution is 
  58. less.  This is what we will call "dithering" and is the subject of this 
  59. paper.  The other tradeoff, i.e., trading color resolution for spatial 
  60. resolution, is called "anti-aliasing" and is not discussed here.  
  61.  
  62. It is important to emphasize here that dithering is a one-way operation.  
  63. Once an image has been dithered, although it may look like a good 
  64. reproduction of the original, information is permanently lost.  Many image 
  65. processing functions fail on dithered images.  For these reasons, dithering 
  66. must be considered only as a way to produce an image on hardware that would 
  67. otherwise be incapable of displaying it.  The data representing an image 
  68. should always be kept in full detail.  
  69.  
  70.  
  71. ========================================================================
  72. Classes of dithering algorithms
  73.  
  74. The classes of dithering algorithms we will discuss here are these:
  75.  
  76. 1.  Random
  77. 2.  Pattern
  78. 3.  Ordered
  79. 4.  Error dispersion
  80.  
  81. Each of these methods is generally better than those listed before it, but 
  82. other considerations such as processing time, memory constraints, etc. may 
  83. weigh in favor of one of the simpler methods.  
  84.  
  85. For the following discussions I will assume that we are given an image with 
  86. 256 shades of gray (0=black..255=white) that we are trying to reproduce on a 
  87. black and white ouput device.  Most of these methods can be extended in 
  88. obvious ways to deal with displays that have more than two levels but fewer 
  89. than the image, or to color images.  Where such extension is not obvious, or 
  90. where better results can be obtained, I will go into more detail.  
  91.  
  92. To convert any of the first three methods into color, simply apply the 
  93. algorithm separately for each primary and mix the resulting values.  This 
  94. assumes that you have at least eight output colors: black, red, green, blue, 
  95. cyan, magenta, yellow, and white.  Though this will work for error dispersion 
  96. as well, there are better methods in this case.  
  97.  
  98.  
  99. ========================================================================
  100. Random dither
  101.  
  102. This is the bubblesort of dithering algorithms.  It is not really acceptable 
  103. as a production method, but it is very simple to describe and implement.  For 
  104. each value in the image, simply generate a random number 1..256; if it is 
  105. geater than the image value at that point, plot the point white, otherwise 
  106. plot it black.  That's it.  This generates a picture with a lot of "white 
  107. noise", which looks like TV picture "snow".  Though the image produced is 
  108. very inaccurate and noisy, it is free from "artifacts" which are phenomena 
  109. produced by digital signal processing.  
  110.  
  111. The most common type of artifact is the Moire pattern (Contributors: please
  112. resist the urge to put an accent on the "e", as no portable character set
  113. exists for this).  If you draw several lines close together radiating from a 
  114. single point on a computer display, you will see what appear to be flower-
  115. like patterns.  These patterns are not part of the original idea of lines, 
  116. but are an illusion produced by the jaggedness of the display.  
  117.  
  118. Many techniques exist for the reduction of digital artifacts like these, most 
  119. of which involve using a little randomness to "perturb" a regular algorithm a 
  120. little.  Random dither obviously takes this to extreme.  
  121.  
  122. I should mention, of course, that unless your computer has a hardware-based 
  123. random number generator (and most don't) there may be some artifacts from the 
  124. random number generation algorithm itself.  
  125.  
  126. While random dither adds a lot of high-frequency noise to a picture, it is 
  127. useful in reproducing very low-frequency images where the absence of 
  128. artifacts is more important than noise.  For example, a whole screen 
  129. containing a gradient of all levels from black to white would actually look 
  130. best with a random dither.  In this case, ordered dithering would produce 
  131. diagonal patterns, and error dispersion would produce clustering.  
  132.  
  133. For efficiency, you can take the random number generator "out of the loop" by 
  134. generating a list of random numbers beforehand for use in the dither.  Make 
  135. sure that the list is larger than the number of pixels in the image or you 
  136. may get artifacts from the reuse of numbers.  The worst case would be if the 
  137. size of your list of random numbers is a multiple or near-multiple of the 
  138. horizontal size of the image, in which case unwanted vertical or diagonal 
  139. lines will appear.  
  140.  
  141.  
  142. ========================================================================
  143. Pattern dither
  144.  
  145. This is also a simple concept, but much more effective than random dither.  
  146. For each possible value in the image, create a pattern of dots that 
  147. approximates that value.  For instance, a 3-by-3 block of dots can have one 
  148. of 512 patterns, but for our purposes, there are only 10; the number of black 
  149. dots in the pattern determines the darkness of the pattern.  
  150.  
  151. Which 10 patterns do we choose?  Obviously, we need the all-white and all-
  152. black patterns.  We can eliminate those patterns which would create vertical 
  153. or horizontal lines if repeated over a large area because many images have 
  154. such regions of similar value [1].  It has been shown [1] that patterns for 
  155. adjacent colors should be similar to reduce an artifact called "contouring", 
  156. or visible edges between regions of adjacent values.  One easy way to assure 
  157. this is to make each pattern a superset of the previous.  Here are two good 
  158. sets of patterns for a 3-by-3 matrix: 
  159.  
  160.     ---   ---   ---   -X-   -XX   -XX   -XX   -XX   XXX   XXX
  161.     ---   -X-   -XX   -XX   -XX   -XX   XXX   XXX   XXX   XXX
  162.     ---   ---   ---   ---   ---   -X-   -X-   XX-   XX-   XXX
  163. or
  164.     ---   X--   X--   X--   X-X   X-X   X-X   XXX   XXX   XXX
  165.     ---   ---   ---   --X   --X   X-X   X-X   X-X   XXX   XXX
  166.     ---   ---   -X-   -X-   -X-   -X-   XX-   XX-   XX-   XXX
  167.  
  168. The first set of patterns above are "clustered" in that as new dots are added 
  169. to each pattern, they are added next to dots already there.  The second set 
  170. is "dispersed" as the dots are spread out more.  This distinction is more 
  171. important on larger patterns.  Dispersed-dot patterns produce less grainy 
  172. images, but require that the output device render each dot distinctly.  When 
  173. this is not the case, as with a printing press which smears the dots a 
  174. little, clustered patterns are better.  
  175.  
  176. For each pixel in the image we now print the pattern which is closest to its 
  177. value.  This will triple the size of the image in each direction, so this 
  178. method can only be used where the display spatial resolution is much greater 
  179. than that of the image.  
  180.  
  181. We can exploit the fact that most images have large areas of similar value to 
  182. reduce our need for extra spatial resolution.  Instead of plotting a whole 
  183. pattern for each pixel, map each pixel in the image to a dot in the pattern 
  184. an only plot the corresponding dot for each pixel.  
  185.  
  186. The simplest way to do this is to map the X and Y coordinates of each pixel 
  187. into the dot (X mod 3, Y mod 3) in the pattern.  Large areas of constant 
  188. value will come out as repetitions of the pattern as before.  
  189.  
  190. To extend this method to color images, we must use patterns of colored dots 
  191. to represent shades not directly printable by the hardware.  For example, if 
  192. your hardware is capable of printing only red, green, blue, and black (the 
  193. minimal case for color dithering), other colors can be represented with 
  194. patterns of these four: 
  195.  
  196.     Yellow = R G    Cyan = G B      Magenta = R B       Gray = R G
  197.              G R           B G                B R              B K
  198.  
  199. (B here represents blue, K is black).  There are a total of 31 such distinct 
  200. patterns which can be used; I will leave their enumeration "as an exercise 
  201. for the reader" (don't you hate books that do that?).  
  202.  
  203.  
  204. ========================================================================
  205. Ordered dither
  206.  
  207. Because each of the patterns above is a superset of the previous, we can 
  208. express the patterns in compact form as the order of dots added: 
  209.  
  210.         8  3  4          and          1  7  4
  211.         6  1  2                       5  8  3
  212.         7  5  9                       6  2  9
  213.  
  214. Then we can simply use the value in the array as a threshhold.  If the value 
  215. of the pixel (scaled into the 0-9 range) is less than the number in the 
  216. corresponding cell of the matrix, plot that pixel black, otherwise, plot it 
  217. white.  This process is called ordered dither.  As before, clustered patterns 
  218. should be used for devices which blur dots.  In fact, the clustered pattern 
  219. ordered dither is the process used by most newspapers, and the term 
  220. halftoning refers to this method if not otherwise qualified.  
  221.  
  222. Bayer [2] has shown that for matrices of orders which are powers of two there 
  223. is an optimal pattern of dispersed dots which results in the pattern noise 
  224. being as high-frequency as possible.  The pattern for a 2x2 and 4x4 matrices 
  225. are as follows: 
  226.  
  227.         1  3        1  9  3 11        These patterns (and their rotations
  228.         4  2       13  5 15  7        and reflections) are optimal for a
  229.                     4 12  2 10        dispersed-pattern ordered dither.
  230.                    16  8 14  6
  231.  
  232. Ulichney [3] shows a recursive technique can be used to generate the larger 
  233. patterns.  To fully reproduce our 256-level image, we would need to use the 
  234. 8x8 pattern.  
  235.  
  236. Bayer's method is in very common use and is easily identified by the cross-
  237. hatch pattern artifacts it produces in the resulting display.  This 
  238. artifacting is the major drawback of the technique wich is otherwise very 
  239. fast and powerful.  Ordered dithering also performs very badly on images 
  240. which have already been dithered to some extent.  As stated earlier, 
  241. dithering should be the last stage in producing a physical display from a 
  242. digitally stored image.  The dithered image should never be stored itself.  
  243.  
  244.  
  245. ========================================================================
  246. Error dispersion
  247.  
  248. This technique generates the best results of any method here, and is 
  249. naturally the slowest.  In fact, there are many variants of this technique as 
  250. well, and the better they get, the slower they are.  
  251.  
  252. Error dispersion is very simple to describe: for each point in the image, 
  253. first find the closest color available.  Calculate the difference between the 
  254. value in the image and the color you have.  Now divide up these error values 
  255. and distribute them over the neighboring pixels which you have not visited 
  256. yet.  When you get to these later pixels, just add the errors distributed 
  257. from the earlier ones, clip the values to the allowed range if needed, then 
  258. continue as above.  
  259.  
  260. If you are dithering a grayscale image for output to a black-and-white 
  261. device, the "find closest color" is just a simle threshholding operation.  In 
  262. color, it involves matching the input color to the closest available hardware 
  263. color, which can be difficult depending on the hardware palette.  
  264.  
  265. There are many ways to distribute the errors and many ways to scan the
  266. image, but I will deal here with only a few.  The two basic ways to scan the
  267. image are with a normal left-to-right, top-to-bottom raster, or with an
  268. alternating left-to-right then right-to-left raster.  The latter method
  269. generally produces fewer artifacts and can be used with all the error
  270. diffusion patterns discussed below.
  271.  
  272. The different ways of dividing up the error can be expressed as patterns 
  273. (called filters, for reasons too boring to go into here).
  274.  
  275.                  X   7            This is the Floyd and Steinberg [4]
  276.              3   5   1            error diffusion filter.
  277.  
  278. In this filter, the X represents the pixel you are currently scanning, and
  279. the numbers (called weights, for equally boring reasons) represent the 
  280. proportion of the error distributed to the pixel in that position.  Here, the 
  281. pixel immediately to the right gets 7/16 of the error (the divisor is 16 
  282. because the weights add to 16), the pixel directly below gets 5/16 of the 
  283. error, and the diagonally adjacent pixels get 3/16 and 1/16.  When scanning a 
  284. line right-to-left, this pattern is reversed.  This pattern was chosen 
  285. carefully so that it would produce a checkerboard pattern in areas with 
  286. intensity of 1/2 (or 128 in our image).  It is also fairly easy to calculate 
  287. when the division by 16 is replaced by shifts.  
  288.  
  289. Another filter in common use, but not recommended:
  290.  
  291.                  X   3            A simpler filter.
  292.                  3   2
  293.  
  294. This is often erroneously called the Floyd-Steinberg filter, but it does not
  295. produce as good results.  An alternating raster scan of the image is
  296. necessary with this filter to reduce artifacts.  Additional perturbations of
  297. the formula are frequently necessary also.
  298.  
  299. Burke [5] suggests the following filter:
  300.  
  301.                  X   8   4        The Burke filter.
  302.          2   4   8   4   2
  303.  
  304. Notice that this is just a simplification of the Stucki filter (below) with
  305. the bottom row removed.  The main improvement is that the divisor is now 32,
  306. which makes calculating the errors faster, and the removal of one row
  307. reduces the memory requirements of the method.
  308.  
  309. This is also fairly easy to calculate and produces better results than Floyd 
  310. and Steinberg.  Jarvis, Judice, and Ninke [6] use the following: 
  311.  
  312.                  X   7   5        The Jarvis, et al. pattern.
  313.          3   5   7   5   3
  314.          1   3   5   3   1
  315.  
  316. The divisor here is 48, which is a little more expensive to calculate, and 
  317. the errors are distributed over three lines, requiring extra memory and time 
  318. for processing.  Probably the best filter is from Stucki [7]: 
  319.  
  320.                  X   8   4        The Stucki pattern.
  321.          2   4   8   4   2
  322.          1   2   4   2   1
  323.  
  324. This one takes a division by 42 for each pixel and is therefore slow if math 
  325. is done inside the loop.  After the initial 8/42 is calculated, some time can 
  326. be saved by producing the remaining fractions by shifts.  
  327.  
  328. The speed advantages of the simpler filters can be eliminated somewhat by
  329. performing the divisions beforehand and using lookup tables instead of per-
  330. forming math inside the loop.  This makes it harder to use various filters
  331. in the same program, but the speed benefits are enormous.
  332.  
  333. It is critical with all of these algorithms that when error values are added
  334. to neighboring pixels, the values must be truncated to fit within the limits
  335. of hardware, otherwise and area of very intense color may cause streaks into
  336. an adjacent area of less intense color.  This truncation adds noise to the
  337. image anagous to clipping in an audio amplifier, but it is not nearly so 
  338. offensive as the streaking.  It is mainly for this reason that the larger 
  339. filters work better--they split the errors up more finely and produce less of 
  340. this clipping noise.  
  341.  
  342. With all of these filters, it is also important to ensure that the errors
  343. you distribute properly add to the original error value.  This is easiest to 
  344. accomplish by subtracting each fraction from the whole error as it is 
  345. calculated, and using the final remainder as the last fraction.  
  346.  
  347. Some of these methods (particularly the simpler ones) can be greatly improved 
  348. by skewing the weights with a little randomness [3].  
  349.  
  350. Calculating the "nearest available color" is trivial with a monochrome image; 
  351. with color images it requires more work.  A table of RGB values of all 
  352. available colors must be scanned sequentially for each input pixel to find 
  353. the closest.  The "distance" formula most often used is a simple pythagorean 
  354. "least squares".  The difference for each color is squared, and the three 
  355. squares added to produce the distance value.  This value is equivalent to the 
  356. square of the distance between the points in RGB-space.  It is not necessary 
  357. to compute the square root of this value because we are not interested in the 
  358. actual distance, only in which is smallest.  The square root function is a 
  359. monotonic increasing function and does not affect the order of its operands.  
  360. If the total number of colors with which you are dealing is small, this part 
  361. of the algorithm can be replaced by a lookup table as well.
  362.  
  363. When your hardware allows you to select the available colors, very good 
  364. results can be achieved by selecting colors from the image itself.  You must 
  365. reserve at least 8 colors for the primaries, secondaries, black, and white 
  366. for best results.  If you do not know the colors in your image ahead of time, 
  367. or if you are going to use the same map to dither several different images, 
  368. you will have to fill your color map with a good range of colors.  This can 
  369. be done either by assigning a certain number of bits to each primary and 
  370. computing all combinations, or by a smoother distribution as suggested by 
  371. Heckbert [8].  
  372.  
  373.  
  374. ========================================================================
  375. Sample code
  376.  
  377. Despite my best efforts in expository writing, nothing explains an algorithm 
  378. better than real code.  With that in mind, presented here below is an 
  379. algorithm (in somewhat incomplete, very inefficient pseudo-C) which 
  380. implements error diffusion dithering with the Floyd and Steinberg filter.  It 
  381. is not efficiently coded, but its purpose is to show the method, which I 
  382. believe it does.  
  383.  
  384. /* Floyd/Steinberg error diffusion dithering algorithm in color.  The array
  385. ** line[][] contains the RGB values for the current line being processed;
  386. ** line[0][x] = red, line[1][x] = green, line[2][x] = blue.  It uses the
  387. ** external functions getline() and putdot(), whose pupose should be easy
  388. ** to see from the code.
  389. */
  390.  
  391. unsigned char line[3][WIDTH];
  392. unsigned char colormap[3][COLORS] = {
  393.       0,   0,   0,     /* Black       This color map should be replaced   */
  394.     255,   0,   0,     /* Red         by one available on your hardware.  */
  395.       0, 255,   0,     /* Green       It may contain any number of colors */
  396.       0,   0, 255,     /* Blue        as long as the constant COLORS is   */
  397.     255, 255,   0,     /* Yellow      set correctly.                      */
  398.     255,   0, 255,     /* Magenta                                         */
  399.       0, 255, 255,     /* Cyan                                            */
  400.     255, 255, 255 };   /* White                                           */
  401.  
  402. int getline();               /* Function to read line[] from image file;  */
  403.                              /* must return EOF when done.                */
  404. putdot(int x, int y, int c); /* Plot dot of color c at location x, y.     */
  405.  
  406. dither()
  407. {
  408.     static int ed[3][WIDTH] = {0};      /* Errors distributed down, i.e., */
  409.                                         /* to the next line.              */
  410.     int x, y, h, c, nc, v,              /* Working variables              */
  411.         e[4],                           /* Error parts (7/8,1/8,5/8,3/8). */
  412.         ef[3];                          /* Error distributed forward.     */
  413.     long dist, sdist;                   /* Used for least-squares match.  */
  414.  
  415.     for (x=0; x<WIDTH; ++x) {
  416.         ed[0][x] = ed[1][x] = ed[2][x] = 0;
  417.     }
  418.     y = 0;                              /* Get one line at a time from    */
  419.     while (getline() != EOF) {          /* input image.                   */
  420.  
  421.         ef[0] = ef[1] = ef[2] = 0;      /* No forward error for first dot */
  422.  
  423.         for (x=0; x<WIDTH; ++x) {
  424.             for (c=0; c<3; ++c) {
  425.                 v = line[c][x] + ef[c] + ed[c][x];  /* Add errors from    */
  426.                 if (v < 0) v = 0;                   /* previous pixels    */
  427.                 if (v > 255) v = 255;               /* and clip.          */
  428.                 line[c][x] = v;
  429.             }
  430.  
  431.             sdist = 255L * 255L * 255L + 1L;        /* Compute the color  */
  432.             for (c=0; c<COLORS; ++c) {              /* in colormap[] that */
  433.                                                     /* is nearest to the  */
  434. #define D(z) (line[z][x]-colormap[c][z])            /* corrected color.   */
  435.  
  436.                 dist = D(0)*D(0) + D(1)*D(1) + D(2)*D(2);
  437.                 if (dist < sdist) {
  438.                     nc = c;
  439.                     sdist = dist;
  440.                 }
  441.             }
  442.             putdot(x, y, nc);           /* Nearest color found; plot it.  */
  443.  
  444.             for (c=0; c<3; ++c) {
  445.                 v = line[c][x] - colormap[c][nc];   /* V = new error; h = */
  446.                 h = v >> 1;                         /* half of v, e[1..4] */
  447.                 e[1] = (7 * h) >> 3;                /* will be filled     */
  448.                 e[2] = h - e[1];                    /* with the Floyd and */
  449.                 h = v - h;                          /* Steinberg weights. */
  450.                 e[3] = (5 * h) >> 3;
  451.                 e[4] = h = e[3];
  452.  
  453.                 ef[c] = e[1];                       /* Distribute errors. */
  454.                 if (x < WIDTH-1) ed[c][x+1] = e[2];
  455.                 if (x == 0) ed[c][x] = e[3]; else ed[c][x] += e[3];
  456.                 if (x > 0) ed[c][x-1] += e[4];
  457.             }
  458.         } /* next x */
  459.  
  460.         ++y;
  461.     } /* next y */
  462. }
  463.  
  464.  
  465. ========================================================================
  466. Bibliography
  467.  
  468. [1] Foley, J. D. and Andries Van Dam (1982)
  469.     Fundamentals of Interactive Computer Graphics.  Reading, MA: Addisson 
  470.     Wesley.  
  471.  
  472.     This is a standard reference for many graphic techniques which has not 
  473.     declined with age.  Highly recommended.  
  474.  
  475. [2] Bayer, B. E. (1973)
  476.     "An Optimum Method for Two-Level Rendition of Continuous Tone Pictures," 
  477.     IEEE International Conference on Communications, Conference Records, pp.  
  478.     26-11 to 26-15.  
  479.  
  480.     A short article proving the optimality of Bayer's pattern in the 
  481.     dispersed-dot ordered dither.  
  482.  
  483. [3] Ulichney, R. (1987)
  484.     Digital Halftoning.  Cambridge, MA: The MIT Press.
  485.  
  486.     This is the best book I know of for describing the various black and 
  487.     white dithering methods.  It has clear explanations (a little higher math 
  488.     may come in handy) and wonderful illustrations.  It does not contain any 
  489.     code, but don't let that keep you from getting this book.  Computer 
  490.     Literacy carries it but is often sold out.  
  491.  
  492. [4] Floyd, R.W. and L. Steinberg (1975)
  493.     "An Adaptive Algorithm for Spatial Gray Scale."  SID International 
  494.     Symposium Digest of Technical Papers, vol 1975m, pp. 36-37.  
  495.  
  496.     Short article in which Floyd and Steinberg introduce their filter.  
  497.  
  498. [5] Daniel Burkes is unpublished, but can be reached at this address:
  499.  
  500.     Daniel Burkes
  501.     TerraVision Inc.
  502.     2351 College Station Road Suite 563
  503.     Athens, GA  30305
  504.  
  505.     or via CompuServe's Graphics Support Forum, ID # 72077,356.  
  506.  
  507. [6] Jarvis, J. F., C. N. Judice, and W. H. Ninke (1976)
  508.     "A Survey of Techniques for the Display of Continuous Tone Pictures on 
  509.     Bi-Level Displays."  Computer Graphics and Image Processing, vol. 5, pp. 
  510.     13-40.  
  511.  
  512. [7] Stucki, P. (1981)
  513.     "MECCA - a multiple-error correcting computation algorithm for bilevel 
  514.     image hardcopy reproduction."  Research Report RZ1060, IBM Research 
  515.     Laboratory, Zurich, Switzerland.  
  516.  
  517. [8] Heckbert, Paul (9182)
  518.     "Color Image Quantization for Frame Buffer Display."  Computer Graphics 
  519.     (SIGGRAPH 82), vol. 16, pp. 297-307.  
  520.  
  521.  
  522. ========================================================================
  523. Other works of interest:
  524.  
  525. Newman, William M., and Robert F. S. Sproull (1979)
  526. Principles of Interactive Computer Graphics.  2nd edition.  New York:
  527. McGraw-Hill.
  528.  
  529. Rogers, David F. (1985)
  530. Procedural Elements for Computer Graphics.  New York: McGraw-Hill.
  531.  
  532. Rogers, David F., and J. A. Adams (1976)
  533. Mathematical Elements for Computer Graphics.  New York: McGraw-Hill.
  534.  
  535.  
  536. ========================================================================
  537. About CompuServe Graphics Support Forum:
  538.  
  539. CompuServe Information Service is a service of the H&R Block companies 
  540. providing computer users with electronic mail, teleconferencing, and many 
  541. other telecommunications services.  Call 800-848-8199 for more information.  
  542.  
  543. The Graphics Support Forum is dedicated to helping its users get the most out 
  544. of their computers' graphics capabilities.  It has a small staff and a large 
  545. number of "Developers" who create images and software on all types of 
  546. machines from Apple IIs to Sun workstations.  While on CompuServe, type GO 
  547. PICS from any "!" prompt to gain access to the forum.  
  548.  
  549.